// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.core.metadata;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.dengues.commons.connectivity.IConnectivitySettingsConstants;
import org.dengues.commons.utils.DenguesTextUtil;
import org.dengues.core.components.ENodeParameterName;
import org.dengues.core.connectivity.IConnectivityProperty;
import org.dengues.core.metadata.types.MetadataTypesManager;
import org.dengues.core.resource.DenguesProjectFactory;
import org.dengues.model.DenguesModelManager;
import org.dengues.model.database.DBColumn;
import org.dengues.model.database.DBTable;
import org.dengues.model.database.DatabaseDiagram;
import org.dengues.model.database.DatabaseFactory;
import org.dengues.model.database.DiagramChild;
import org.dengues.model.database.ForeignKey;
import org.dengues.model.project.ConnPropertySetType;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.common.util.EList;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Display;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2007-12-12 qiang.zhang $
 * 
 */
public class MetadataHelper {

    public static final String FK_LINKTO = "->";

    public static final String FK_SEQ = ".";

    public static final String FK_NAME = "FK_NAME";

    public static final int TABLE_HEADER = 23;

    public static final int COLUMN_HEIGHT = 26;

    private static final String NEW_COLUMN = "newColumn_"; //$NON-NLS-1$

    private static final String NEW_TABLE = "newTable_"; //$NON-NLS-1$

    private static final String NEW_FK = "FK_"; //$NON-NLS-1$

    private static int computeY(DBColumn column) {
        DBTable table = column.getTable();
        int y = table.getY() + TABLE_HEADER;
        int index = table.getColumns().indexOf(column) + 1;
        y += index * column.getHeight();
        return y;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getColumnLocation".
     * 
     * @param key
     * @return
     */
    public static Point getColumnLocation(ForeignKey key) {
        Point point = new Point();

        int x = key.getSource().getTable().getX();
        int x2 = key.getTarget().getTable().getX();

        int width = x2 > x ? key.getSource().getTable().getWidth() : key.getTarget().getTable().getWidth();
        int abs = Math.abs(x2 - x) / 2 - width / 2;
        int px = x2 > x ? x + abs + width : x2 + abs + width;

        GC gc = new GC(Display.getDefault());
        org.eclipse.swt.graphics.Point stringExtent = gc.stringExtent(key.getName());
        gc.dispose();
        px = px - stringExtent.x / 2;
        point.x = px;

        int y = MetadataHelper.computeY(key.getSource());
        int y2 = MetadataHelper.computeY(key.getTarget());

        int height = key.getTarget().getHeight();
        abs = Math.abs(y2 - y) / 2 - height / 2;
        int py = y2 > y ? y + abs + height : y2 + abs + height;
        py = py - stringExtent.y;
        point.y = py;
        return point;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "convertMetadataTable".
     * 
     * @param table
     * @return
     */
    public static MetadataTable convertMetadataTable(DBTable table) {
        MetadataTable metadataTable = new MetadataTable();
        metadataTable.setTableName(table.getName());
        List<DBColumn> columns = table.getColumns();
        List<MetadataColumn> columnList = new ArrayList<MetadataColumn>();
        for (DBColumn column : columns) {
            MetadataColumn metadataColumn = new MetadataColumn();
            metadataColumn.setColumnName(column.getName());
            metadataColumn.setDefaut(column.getDefaultValue());
            metadataColumn.setKey(column.isKey());
            metadataColumn.setForeignKey(column.isForeignKey());
            metadataColumn.setLength(column.getLength());
            metadataColumn.setNullable(column.isNullable());
            metadataColumn.setPattern(column.getPattern());
            metadataColumn.setPrecision(column.getPrecision());
            metadataColumn.setType(column.getType());
            metadataColumn.setSelected(column.isSelected());
            metadataColumn.setComment(DenguesTextUtil.getNotNullString((String) column.getProperties().get(
                    ENodeParameterName.DB_COLUMN_COMMENT.getName())));
            columnList.add(metadataColumn);
            metadataColumn.setMetadataTable(metadataTable);
        }
        metadataTable.setColumns(columnList);
        return metadataTable;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "convertDBTable".
     * 
     * @param metadataTable
     * @return
     */
    public static List<DBColumn> convertDBTable(MetadataTable metadataTable) {
        List<MetadataColumn> columns = metadataTable.getColumns();
        List<DBColumn> columnList = new ArrayList<DBColumn>();
        for (MetadataColumn column : columns) {
            DBColumn metadataColumn = DatabaseFactory.eINSTANCE.createDBColumn();
            metadataColumn.setName(column.getColumnName());
            metadataColumn.setDefaultValue(column.getDefaut());
            metadataColumn.setKey(column.isKey());
            metadataColumn.setSelected(column.isSelected());
            metadataColumn.setForeignKey(column.isForeignKey());
            metadataColumn.setLength(column.getLength());
            metadataColumn.setNullable(column.isNullable());
            metadataColumn.setPattern(column.getPattern());
            metadataColumn.setPrecision(column.getPrecision());
            metadataColumn.setType(column.getType());
            metadataColumn.setX(0);
            metadataColumn.setY(columnList.size() * 20);
            metadataColumn.setHeight(20);
            metadataColumn.getProperties().put(ENodeParameterName.DB_COLUMN_COMMENT.getName(), column.getComment());
            columnList.add(metadataColumn);
        }
        return columnList;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "generateNewColumn".
     * 
     * @param metadataTable
     * @return
     */
    public static MetadataColumn generateNewColumn(MetadataTable metadataTable) {

        MetadataColumn metadataColumn = new MetadataColumn();
        i = 0;
        List<String> list = new ArrayList<String>();
        for (MetadataColumn c : metadataTable.getColumns()) {
            String columnName = c.getColumnName();
            if (columnName.startsWith(NEW_COLUMN)) {
                list.add(columnName);
            }
        }
        Collections.sort(list);
        metadataColumn.setColumnName(generateNewCloumnName(list, null));
        metadataColumn.setType(MetadataTypesManager.getInstance().getDefaultDBTypeLabel());
        metadataColumn.setMetadataTable(metadataTable);
        return metadataColumn;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "generateNewTableName".
     * 
     * @param diagram
     * @param string
     * @return
     */
    public static String generateNewTableName(DatabaseDiagram diagram, String string) {
        String prefix = NEW_TABLE;
        if (string != null && !"".equals(string)) { //$NON-NLS-1$
            prefix = string;
        }
        if (diagram == null) {
            return prefix;
        }
        i = 0;
        List<String> list = new ArrayList<String>();
        for (Object c : diagram.getDbChildren()) {
            if (c instanceof DBTable) {
                String columnName = ((DBTable) c).getName();
                if (columnName.startsWith(prefix)) {
                    list.add(columnName);
                }
            }
        }
        Collections.sort(list);
        for (String columnName : list) {
            String num = columnName.substring(prefix.length());
            if (num.equals((new Integer(i)).toString())) {
                i++;
            }
        }
        return prefix + i;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "generateNewColumnName".
     * 
     * @param table
     * @param string
     * @return
     */
    public static String generateNewColumnName(DBTable table, String string) {
        String prefix = NEW_COLUMN;
        if (string != null && !"".equals(string)) { //$NON-NLS-1$
            prefix = string;
        }
        i = 0;
        List<String> list = new ArrayList<String>();
        for (DBColumn c : table.getColumns()) {
            String columnName = c.getName();
            if (columnName.startsWith(prefix)) {
                list.add(columnName);
            }
        }
        Collections.sort(list);
        if (list.isEmpty()) {
            return prefix;
        }
        return generateNewCloumnName(list, prefix);
    }

    private static int i = 0;

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "generateNewCloumnName".
     * 
     * @param list
     * @return
     */
    private static String generateNewCloumnName(List<String> list, String prefix) {
        if (prefix == null) {
            prefix = NEW_COLUMN;
        }
        for (String columnName : list) {
            String num = columnName.substring(prefix.length());
            if (num.equals((new Integer(i)).toString())) {
                i++;
            }
        }
        return prefix + i;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "cloneDBTable".
     * 
     * @param table
     * @return
     */
    public static DBTable cloneDBTable(DBTable table) {
        DBTable table2 = DenguesModelManager.getDatabaseFactory().createDBTable();
        table2.setOnlyRead(table.isOnlyRead());
        table2.setSelected(table.isSelected());
        table2.setName(table.getName());
        table2.setHeight(table.getHeight());
        table2.setWidth(table.getWidth());
        table2.setX(table.getX());
        table2.setY(table.getY());
        HashMap properties = table.getProperties();
        for (Object obj : properties.keySet()) {
            table2.getProperties().put(obj, properties.get(obj));
        }
        EList columns = table.getColumns();
        for (Object object : columns) {
            DBColumn column = (DBColumn) object;
            table2.getColumns().add(cloneDBColumn(column));
        }
        return table2;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "cloneDBColumn".
     * 
     * @param column
     * @return
     */
    public static DBColumn cloneDBColumn(DBColumn column) {
        DBColumn metadataColumn = DenguesModelManager.getDatabaseFactory().createDBColumn();
        HashMap properties = column.getProperties();
        for (Object obj : properties.keySet()) {
            metadataColumn.getProperties().put(obj, properties.get(obj));
        }
        metadataColumn.setName(column.getName());
        metadataColumn.setDefaultValue(column.getDefaultValue());
        metadataColumn.setKey(column.isKey());
        metadataColumn.setSelected(column.isSelected());
        metadataColumn.setForeignKey(column.isForeignKey());
        metadataColumn.setLength(column.getLength());
        metadataColumn.setNullable(column.isNullable());
        metadataColumn.setPattern(column.getPattern());
        metadataColumn.setPrecision(column.getPrecision());
        metadataColumn.setType(column.getType());
        metadataColumn.setX(0);
        metadataColumn.setHeight(20);

        return metadataColumn;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getForeignKeyUname".
     * 
     * @param key
     * @return
     */
    public static String getForeignKeyUname(ForeignKey key) {
        return key.getSource().getTable().getName() + FK_SEQ + key.getSource().getName() + FK_LINKTO
                + key.getTarget().getTable().getName() + FK_SEQ + key.getTarget().getName();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFKByUnqiueName".
     * 
     * @param unName
     * @return
     */
    public static ForeignKey getFKByUnqiueName(String unName, DatabaseDiagram diagram) {
        EList<DiagramChild> dbChildren = diagram.getDbChildren();
        for (DiagramChild diagramChild : dbChildren) {
            if (diagramChild instanceof DBTable) {
                DBTable table = (DBTable) diagramChild;
                EList columns = table.getColumns();
                for (Object object3 : columns) {
                    DBColumn object32 = (DBColumn) object3;
                    EList<ForeignKey> outputs = object32.getOutputs();
                    for (ForeignKey foreignKey : outputs) {
                        if (unName.equals(getForeignKeyUname(foreignKey))) {
                            return foreignKey;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "generateNewForeignKeyName".
     * 
     * @param source
     * @return
     */
    public static String generateNewForeignKeyName(DBColumn source) {
        DBTable table = source.getTable();
        return NEW_FK + table.getName() + "_" + source.getName(); //$NON-NLS-1$
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getConnSetType".
     * 
     * @param diagram
     * @return
     */
    public static ConnPropertySetType getConnSetType(DatabaseDiagram diagram) {
        EList<ConnPropertySetType> connProperties = DenguesProjectFactory.getDenguesProject().getProjectType()
                .getConnProperties();
        ConnPropertySetType setType = null;
        String connId = diagram.getConnId();
        for (ConnPropertySetType cpst : connProperties) {
            String split = cpst.getId().substring(IConnectivitySettingsConstants.PROP_DEFN.length() + 1);
            String string = split + IConnectivitySettingsConstants.CONNECTIVITY_DELIMITER + cpst.getName();
            if (string.equals(connId)) {
                setType = cpst;
            }
        }
        return setType;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getConnSetType".
     * 
     * @param diagram
     * @return
     */
    public static ConnPropertySetType getConnSetType(String connId) {
        EList<ConnPropertySetType> connProperties = DenguesProjectFactory.getDenguesProject().getProjectType()
                .getConnProperties();
        ConnPropertySetType setType = null;
        for (ConnPropertySetType cpst : connProperties) {
            String split = cpst.getId().substring(IConnectivitySettingsConstants.PROP_DEFN.length() + 1);
            String string = split + IConnectivitySettingsConstants.CONNECTIVITY_DELIMITER + cpst.getName();
            if (string.equals(connId)) {
                setType = cpst;
            }
        }
        return setType;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getConnSetType".
     * 
     * @param diagram
     * @return
     */
    public static ConnPropertySetType getConnSetType(IConnectivityProperty res) {
        ConnPropertySetType setType = null;
        EList<ConnPropertySetType> connProperties = DenguesProjectFactory.getDenguesProject().getProjectType()
                .getConnProperties();
        for (ConnPropertySetType cset : connProperties) {
            if (res.getId().equals(cset.getId()) && res.getName().equals(cset.getName()) && setType != cset) {
                setType = cset;
                break;
            }
        }
        return setType;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "fixedTablesLocation".
     * 
     * @param diagram
     * @param table
     */
    public static void fixedTablesLocation(DatabaseDiagram diagram, DBTable table) {
        table.setX(32 + diagram.getDbChildren().size() * 180);
        table.setY(32);
        table.setSycdb(true);
        diagram.getDbChildren().add(table);
    }
}
